#ifndef _DB_H__
#define _DB_H__
#include "util.hpp"
#include <mutex>
#include <assert.h>
class user_table{
private:
    MYSQL* _mysql;//操作句柄
    std::mutex _mutex;//互斥锁保护数据库数据
public:
    user_table(
        const std::string &host,
        const std::string &user,
        const std::string &pass,
        const std::string &db,
        uint16_t port = 3306
    )
    {
        _mysql = mysql_util::mysql_create(host, user, pass, db, port);
        assert(_mysql != NULL);
    }
    ~user_table()
    {
        mysql_util::mysql_destroy(_mysql);
        _mysql = NULL;
    }
    bool insert(Json::Value& user)//注册时新增用户
    {
        #define INSERT_USER "insert user values(null, '%s', password('%s'), 1000, 0,0);"
        // sprintf(void *buf, char *format, ...)
        if (user["password"].isNull() || user["username"].isNull()) {
            DBG_LOG("INPUT PASSWORD OR USERNAME");
            return false;
        }
        char sql[4096] = {0};
        sprintf(sql, INSERT_USER, user["username"].asCString(), user["password"].asCString());
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false) {
            DBG_LOG("insert user info failed!!\n");
            return false;
        }
        return true;
    }

    //登录验证，并返回详细的⽤⼾信息
    bool login(Json::Value &user) {
        if (user["password"].isNull() || user["username"].isNull()) 
        {
            DBG_LOG("INPUT PASSWORD OR USERNAME");
            return false;
        }
        //以⽤⼾名和密码共同作为查询过滤条件，查询到数据则表⽰⽤⼾名密码⼀致，没有信息则⽤⼾名密码错误
        #define LOGIN_USER "select id, score, total_count, win_count from user where username='%s' and password=password('%s');"
        char sql[4096] = {0};
        sprintf(sql, LOGIN_USER, user["username"].asCString(), user["password"].asCString());
        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false) 
            {
                DBG_LOG("user login failed!!\n");
                return false;
            }
            //按理说要么有数据，要么没有数据，就算有数据也只能有⼀条数据
            res = mysql_store_result(_mysql);
            if (res == NULL) 
            {
                DBG_LOG("have no login user info!!");
                return false;
            }
        }
        int row_num = mysql_num_rows(res);
        if (row_num != 1) 
        {
            DBG_LOG("the user information queried is not unique!!");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }

    bool select_by_name(const std::string& name, Json::Value& user)//通过用户id获取用户信息
    {
        #define USER_BY_NAME "select id, score, total_count, win_count from user where username='%s';"
        char sql[4096] = {0};
        sprintf(sql, USER_BY_NAME, name.c_str());
        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false) {
                DBG_LOG("get user by name failed!!\n");
                return false;
            }
            //按理说要么有数据，要么没有数据，就算有数据也只能有⼀条数据
            res = mysql_store_result(_mysql);
            if (res == NULL) {
                DBG_LOG("have no user info!!");
                return false;
            }
        }
        int row_num = mysql_num_rows(res);
        if (row_num != 1) {
            DBG_LOG("the user information queried is not unique!!");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["username"] = name;
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true; 
    }

    bool select_by_id(uint64_t id, Json::Value& user)//通过用户id获取用户信息
    {
        #define USER_BY_ID "select username, score, total_count, win_count from user where id=%d;"
        char sql[4096] = {0};
        sprintf(sql, USER_BY_ID, id);
        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false) {
                DBG_LOG("get user by id failed!!\n");
                return false;
            }
            //按理说要么有数据，要么没有数据，就算有数据也只能有⼀条数据
            res = mysql_store_result(_mysql);
            if (res == NULL) {
                DBG_LOG("have no user info!!");
                return false;
            }
        }
        int row_num = mysql_num_rows(res);
        if (row_num != 1) {
            DBG_LOG("the user information queried is not unique!!");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)id;
        user["username"] = row[0];
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true; 
    }
    bool win(uint64_t id)//胜利时增加信息
    {
        #define USER_WIN "update user set score=score+30, total_count=total_count+1, win_count=win_count+1 where id=%d;"
        char sql[4096] = {0};
        sprintf(sql, USER_WIN, id);
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false) {
            DBG_LOG("update win user info failed!!\n");
            return false;
        }
        return true;
    }
    bool lose(uint64_t id)//失败是增加信息
    {
        #define USER_LOSE "update user set score=score-30, total_count=total_count+1 where id=%d;"
        char sql[4096] = {0};
        sprintf(sql, USER_LOSE, id);
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false) {
            DBG_LOG("update lose user info failed!!\n");
            return false;
        }
        return true;
    }
};

#endif